﻿using System.ComponentModel;
using System.ComponentModel.DataAnnotations.Schema;
using Devonline.Core;
using Devonline.Entity;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Http;

namespace Devonline.CloudService.Tencent.Weixin;

/// <summary>
/// 微信相关终结点
/// 获取 code 一般由客户端进行调用请求, 服务器端接收 code 作为参数, 进行 token 请求
/// get code:           https://open.weixin.qq.com/connect/qrconnect?appid={AppId}&redirect_uri={RedirectUri}&response_type={ResponseType}&scope={Scope}&lang={Language}&state={state}#wechat_redirect
/// 
/// get access key:     https://api.weixin.qq.com/sns/jscode2session?appid={AppId}&secret={Secret}&grant_type={GrantType}&js_code={code}
/// 
/// 获取 token 有两种方式, 带 code 和不带 code 的
/// 以下两种 token 为调用微信接口时的凭证, 需要定时刷新(即重新获取, 此处无 refresh token)
/// get token:          https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={AppId}&secret={Secret}
/// get stable token:   https://api.weixin.qq.com/cgi-bin/stable_token  with post data: { "grant_type": "client_credential", "appid": "AppId", "secret": "Secret", "force_refresh": false }
/// 返回值: 200 -> {"access_token":"ACCESS_TOKEN","expires_in":7200}, 非 200 -> {"errcode":40013,"errmsg":"invalid appid"}
/// 
/// get token:          https://api.weixin.qq.com/sns/oauth2/access_token?appid={AppId}&&secret={Secret}&grant_type={GrantType}&code={code}
/// 返回值如下:
/// 200 ->
/// {
///     "access_token":"ACCESS_TOKEN",
///     "expires_in":7200,
///     "refresh_token":"REFRESH_TOKEN",
///     "openid":"OPENID",
///     "scope":"SCOPE",
///     "is_snapshotuser": 1,
///     "unionid": "UNIONID"
/// }
/// 非 200 -> {"errcode":40029,"errmsg":"invalid code"}
/// 
/// refresh token:      https://api.weixin.qq.com/sns/oauth2/refresh_token?appid={AppId}&grant_type=refresh_token&refresh_token={refreshToken}  with post data: { "grant_type": "client_credential", "appid": "AppId", "secret": "Secret", "force_refresh": false }
/// 200:
/// { 
///     "access_token":"ACCESS_TOKEN",
///     "expires_in":7200,
///     "refresh_token":"REFRESH_TOKEN",
///     "openid":"OPENID",
///     "scope":"SCOPE" 
/// }
/// 非 200: {"errcode":40029,"errmsg":"invalid code"}
/// 
/// check auth:         https://api.weixin.qq.com/sns/auth?access_token={access_token}&openid={openId}
/// 200: { "errcode":0,"errmsg":"ok"}, 非 200: { "errcode":40003,"errmsg":"invalid openid"}
/// 
/// get user info:      https://api.weixin.qq.com/sns/userinfo?access_token={access_token}&openid={openId}
/// 200: {   
///     "openid": "OPENID",
///     "nickname": NICKNAME,
///     "sex": 1,
///     "province":"PROVINCE",
///     "city":"CITY",
///     "country":"COUNTRY",
///     "headimgurl":"https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
///     "privilege":[ "PRIVILEGE1" "PRIVILEGE2" ],
///     "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
/// }
/// 非 200: { "errcode":40003,"errmsg":"invalid openid"}
/// </summary>
public interface IWeixinEndpoint : IAuthEndpoint;

/// <summary>
/// 微信开放平台终结点
/// </summary>
public interface IOpenPlatformEndpoint : IWeixinEndpoint, IAuthEndpoint
{
    /// <summary>
    /// 回调地址
    /// 请使用 urlEncode 对链接进行处理
    /// </summary>
    string RedirectUri { get; set; }
    /// <summary>
    /// 返回类型
    /// </summary>
    string ResponseType { get; set; }
    /// <summary>
    /// 界面语言
    /// 支持cn（中文简体）与en（英文），默认为cn
    /// </summary>
    string Language { get; set; }
}

/// <summary>
/// 微信公众平台平台终结点
/// </summary>
public interface IMediaPlatformEndpoint : IWeixinEndpoint, IAuthEndpoint
{
    /// <summary>
    /// 模板消息参数配置
    /// </summary>
    List<MessageTemplate> MessageTemplates { get; set; }
}

/// <summary>
/// 微信小程序终结点
/// </summary>
public interface IMiniProgramEndpoint : IMediaPlatformEndpoint, IWeixinEndpoint, IAuthEndpoint;

/// <summary>
/// 微信相关终结点
/// 获取 code 一般由客户端进行调用请求, 服务器端接收 code 作为参数, 进行 token 请求
/// get code:           https://open.weixin.qq.com/connect/qrconnect?appid={AppId}&redirect_uri={RedirectUri}&response_type={ResponseType}&scope={Scope}&lang={Language}&state={state}#wechat_redirect
/// 
/// get access key:     https://api.weixin.qq.com/sns/jscode2session?appid={AppId}&secret={Secret}&grant_type={GrantType}&js_code={code}
/// 
/// 获取 token 有两种方式, 带 code 和不带 code 的
/// 以下两种 token 为调用微信接口时的凭证, 需要定时刷新(即重新获取, 此处无 refresh token)
/// get token:          https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={AppId}&secret={Secret}
/// get stable token:   https://api.weixin.qq.com/cgi-bin/stable_token  with post data: { "grant_type": "client_credential", "appid": "AppId", "secret": "Secret", "force_refresh": false }
/// 返回值: 200 -> {"access_token":"ACCESS_TOKEN","expires_in":7200}, 非 200 -> {"errcode":40013,"errmsg":"invalid appid"}
/// 
/// get token:          https://api.weixin.qq.com/sns/oauth2/access_token?appid={AppId}&&secret={Secret}&grant_type={GrantType}&code={code}
/// 返回值如下:
/// 200 ->
/// {
///     "access_token":"ACCESS_TOKEN",
///     "expires_in":7200,
///     "refresh_token":"REFRESH_TOKEN",
///     "openid":"OPENID",
///     "scope":"SCOPE",
///     "is_snapshotuser": 1,
///     "unionid": "UNIONID"
/// }
/// 非 200 -> {"errcode":40029,"errmsg":"invalid code"}
/// 
/// refresh token:      https://api.weixin.qq.com/sns/oauth2/refresh_token?appid={AppId}&grant_type=refresh_token&refresh_token={refreshToken}  with post data: { "grant_type": "client_credential", "appid": "AppId", "secret": "Secret", "force_refresh": false }
/// 200:
/// { 
///     "access_token":"ACCESS_TOKEN",
///     "expires_in":7200,
///     "refresh_token":"REFRESH_TOKEN",
///     "openid":"OPENID",
///     "scope":"SCOPE" 
/// }
/// 非 200: {"errcode":40029,"errmsg":"invalid code"}
/// 
/// check auth:         https://api.weixin.qq.com/sns/auth?access_token={access_token}&openid={openId}
/// 200: { "errcode":0,"errmsg":"ok"}, 非 200: { "errcode":40003,"errmsg":"invalid openid"}
/// 
/// get user info:      https://api.weixin.qq.com/sns/userinfo?access_token={access_token}&openid={openId}
/// 200: {   
///     "openid": "OPENID",
///     "nickname": NICKNAME,
///     "sex": 1,
///     "province":"PROVINCE",
///     "city":"CITY",
///     "country":"COUNTRY",
///     "headimgurl":"https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
///     "privilege":[ "PRIVILEGE1" "PRIVILEGE2" ],
///     "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
/// }
/// 非 200: { "errcode":40003,"errmsg":"invalid openid"}
/// </summary>
public class WeixinEndpoint : AuthEndpoint, IWeixinEndpoint, IAuthEndpoint
{
    public WeixinEndpoint()
    {
        GrantType = "authorization_code";
        Host = "https://api.weixin.qq.com/";
    }
}

/// <summary>
/// 微信开放平台终结点
/// </summary>
public class OpenPlatformEndpoint : WeixinEndpoint, IOpenPlatformEndpoint, IWeixinEndpoint, IAuthEndpoint
{
    /// <summary>
    /// 回调地址
    /// 请使用 urlEncode 对链接进行处理
    /// </summary>
    [Column("redirect_uri"), DisplayName("回调地址")]
    public string RedirectUri { get; set; } = null!;
    /// <summary>
    /// 返回类型
    /// 填 code
    /// </summary>
    [Column("response_type"), DisplayName("返回类型")]
    public string ResponseType { get; set; } = "code";
    /// <summary>
    /// 界面语言
    /// 支持cn（中文简体）与en（英文），默认为cn
    /// </summary>
    [Column("lang"), DisplayName("界面语言")]
    public string Language { get; set; } = "cn";

    /// <summary>
    /// 自配置方法
    /// </summary>
    /// <param name="options"></param>
    public void Configure(OAuthOptions options)
    {
        ArgumentNullException.ThrowIfNull(AppId);
        ArgumentNullException.ThrowIfNull(Secret);
        options.ClientId = AppId;
        options.ClientSecret = Secret;
        options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.CorrelationCookie = new RequestPathBaseCookieBuilder()
        {
            Name = CookieAuthenticationDefaults.AuthenticationScheme,
            HttpOnly = true,
            SameSite = SameSiteMode.None,
            SecurePolicy = CookieSecurePolicy.SameAsRequest,
            IsEssential = true,
        };

        if (Scope is not null)
        {
            options.Scope.AddRange(Scope.Split(AppSettings.CHAR_COMMA, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries));
        }
    }
}

/// <summary>
/// 微信公众平台相关终结点配置
/// </summary>
public class MediaPlatformEndpoint : WeixinEndpoint, IMediaPlatformEndpoint, IWeixinEndpoint, IAuthEndpoint
{
    /// <summary>
    /// 模板消息参数配置
    /// </summary>
    public List<MessageTemplate> MessageTemplates { get; set; } = [];
}

/// <summary>
/// 微信小程序终结点
/// </summary>
public class MiniProgramEndpoint : MediaPlatformEndpoint, IMiniProgramEndpoint, IMediaPlatformEndpoint, IWeixinEndpoint, IAuthEndpoint;

/// <summary>
/// 模板消息模板配置
/// </summary>
public class MessageTemplate
{
    /// <summary>
    /// 消息模板编号, 来自微信公众号
    /// </summary>
    public string Id { get; set; } = null!;
    /// <summary>
    /// 消息模板名字, 用于在代码中查询消息模板
    /// </summary>
    public string Name { get; set; } = null!;
    /// <summary>
    /// 消息模板名字, 来自微信公众号
    /// </summary>
    public string Doc { get; set; } = null!;
    /// <summary>
    /// 消息模板使用的数据对象模型的名字
    /// </summary>
    public string Type { get; set; } = null!;
}